/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.wlq.demo.uitls;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.codec.digest.DigestUtils;

import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * SignUtils.
 */
public final class SignUtils {

    public static final String SIGN_MD5 = "MD5";

    public static final String SIGN_HMD5 = "HMD5";

    public static final String SIGN_HS256 = "HS256";

    public static final String SIGN_HS512 = "HS512";

    private static final Map<String, SignFunction> SIGN_FUNCTION_MAP = ImmutableMap.of(
            SIGN_MD5, (key, data) -> DigestUtils.md5Hex(data + key)
//            SIGN_HMD5, HmacHexUtils::hmacMd5Hex,
//            SIGN_HS256, HmacHexUtils::hmacSha256Hex,
//            SIGN_HS512, HmacHexUtils::hmacSha512Hex
    );

    /**
     * Returns signature of data as hex string (lowercase).
     *
     * @param algorithmName the name of sign algorithm
     * @param key           key
     * @param data          data to sign
     * @return signature
     * @throws NullPointerException          if key or data is null
     * @throws UnsupportedOperationException if algorithmName isn't supported
     */
    public static String sign(final String algorithmName, final String key, final String data) {
        if (Objects.isNull(key) || Objects.isNull(data)) {
            throw new NullPointerException("Key or data is null.");
        }

        return Optional.ofNullable(SIGN_FUNCTION_MAP.get(algorithmName))
                .orElseThrow(() -> new UnsupportedOperationException("unsupported sign algorithm:" + algorithmName))
                .sign(key, data);
    }

    /**
     * Generate key string.
     *
     * @return the string
     */
    public static String generateKey() {
        return UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
    }

    @FunctionalInterface
    private interface SignFunction {
        String sign(String key, String data);
    }

    /**
     * 解析参数
     * @param parm data
     * @return
     */
    public static Map<String,Object> parsingData(String parm){
        String decodeStr = Base64.decodeStr(parm, StandardCharsets.UTF_8);

        String bodyString = dataToJson(decodeStr);

        JSONObject jsonObject = JSONUtil.parseObj(bodyString);

        com.alibaba.fastjson.JSONObject respJson = JSON.parseObject(bodyString, Feature.OrderedField);

        com.alibaba.fastjson.JSONObject jsonObject1 = JSON.parseObject(bodyString);

        Map<String, Object> map = new HashMap<>();

        map.put("dateTime",respJson.get("dateTime"));
        map.put("sign",respJson.get("sign"));

        respJson.remove("dateTime");
        respJson.remove("sign");

        String paramStr = reduction(respJson.toString());

        map.put("param",respJson);
        map.put("paramStr",paramStr);
        return map;
    }

    /**
     * 验证签名
     * @param str 签名
     * @param sign 签名key
     * @param data  生成签名的参数
     * @return
     */
    public static boolean verifySignature(String str, String sign, String data){
        String md5 = sign("MD5", sign, data);
        if (StrUtil.equals(str,md5)){
            return true;
        }
        return false;
    }

    public static String reduction(String str){
        return str.replace("{\"", "").replace("\"}", "").replace("\":\"", "=").replace("\",\"", "&");
    }
    /**
     * 数据转json
     * @param str
     * @return
     */
    public static String dataToJson(String str){
        return "{" + str.replace("&", "',").replace("=", ":'") + "'}";
    }

    /**
     * 判断时间戳
     * @param dataTime 传入时间戳
     * @param range 接受范围
     * @return
     */
    public static boolean determineDateTimeBySeconds(long dataTime, long range) {
        long between = cn.hutool.core.date.DateUtil.between(cn.hutool.core.date.DateUtil.date(dataTime), cn.hutool.core.date.DateUtil.date(DateTime.now().getTime()), DateUnit.SECOND);
        if (between > range){
            return false;
        }
        return true;
    }

}
